/**
 * @fileOverview 
 * Defines helper-functions to aid the conversion of geographical polygons
 * (i.e. polygons on a sphere) to polygons on a plane using Mercator projection.
 * The module also has convenience function to work with polygons from Google
 * Maps API.
 *
 * @author Igor Kulkin <igor.kulkin@gmail.com>
 */


var geoPolygonUtils = geoPolygonUtils || {};


/**
 * @namespace Contains helper functions to convert S2 polygons to R2 polygons.
 * @memberOf geoPolygonUtils
 */
geoPolygonUtils.googleMapsAdapter = geoPolygonUtils.googleMapsAdapter || {};


(function() {

  var Vector = geoPolygonUtils.geometry.Vector;


  /** @exports latlngToMercator as geoPolygonUtils.googleMapsAdapter.latlngToMercator */
  var latlngToMercator =
    /**
     * Converts coordinates on a sphere (specified with latitude and longitude) to coordinates on a plane.
     *
     * @param {Number} lat Latitude in degrees (should be in a range [-180, 180]).
     * @param {Number} lng Longitude in degrees (should be in a range [-90, 90]).
     * @returns {Vector} Vector in R2 space.
     */
    geoPolygonUtils.googleMapsAdapter.latlngToMercator = function(lat, lng) {
      return new Vector((lng + 180) / 360, 0.5 + Math.log(Math.tan(Math.PI * 0.25 - lat * Math.PI / 360)) * 0.5 / Math.PI);
    }


  /** @exports latlngFromMercator as geoPolygonUtils.googleMapsAdapter.latlngFromMercator */
  var latlngFromMercator =
    /**
     * Converts coordinates on a sphere (specified with latitude and longitude) to coordinates on a plane.
     *
     * @param {Vector} vector Vector in R2 space.
     * @returns {Array<Number>} Two-element array with latitude and longitude.
     */
    geoPolygonUtils.googleMapsAdapter.latlngFromMercator = function(vector) {
      return [90 - 360 * Math.atan(Math.exp(Math.PI * (2 * vector.y - 1))) / Math.PI, 360 * vector.x - 180];
    }


  /** @exports metersToMercator as geoPolygonUtils.googleMapsAdapter.metersToMercator */
  var metersToMercator =
    /**
     * Converts a distance in meters to the distance in Mercator projection space.
     * The distance is assumed to be measured along the equator.
     * This function can be used to convert real-life precision constants in meters to
     * precision constants in Mercator projection space.
     *
     * @param {Number} meters Distance in meters.
     * @returns {Number} Distance in mercator projection space.
     */
    geoPolygonUtils.googleMapsAdapter.metersToMercator = function(meters) {
      return meters / 40075696;
    }


  /** @exports polygonFromGPolygon as geoPolygonUtils.googleMapsAdapter.polygonFromGPolygon */
  var polygonFromGPolygon =
    /**
     * Converts a given Google Maps API GPolygon to polygon in a format accepted
     * by geoPolygonUtils library (which is basically an array of vectors).
     *
     * @param {GPolygon} gPolygon
     * @returns {Array<Vector>}
     */
    geoPolygonUtils.googleMapsAdapter.polygonFromGPolygon = function(gPolygon) {
      var vertexCount = gPolygon.getVertexCount();
      if (vertexCount > 0 && gPolygon.getVertex(0).equals(gPolygon.getVertex(vertexCount - 1))) {
        // In Google Maps API a complete closed polygon has the same point as its first and last vertex.
        // I geoPolygonUtils library it's not the case, so we remove the extra vertex.
        vertexCount--;
      }
      var result = [];
      for (var i = 0; i < vertexCount; ++i) {
        var vertex = gPolygon.getVertex(i);
        result.push(latlngToMercator(vertex.lat(), vertex.lng()));
      }
      return result;
    }


  /** @exports polygonToGPolygon as geoPolygonUtils.googleMapsAdapter.polygonToGPolygon */
  var polygonToGPolygon =
    /**
     * Converts a given polygon in a geoPolygonUtils library format to a Google Maps API GPolygon.
     *
     * @param {Array<Vector>} polygon
     * @returns {GPolygon}
     */
    geoPolygonUtils.googleMapsAdapter.polygonToGPolygon = function(polygon) {
      var latlngs = [];
      for (var i = 0; i < polygon.length; ++i) {
        var latlng = latlngFromMercator(polygon[i]);
        latlngs.push(new GLatLng(latlng[0], latlng[1]));
      }
      var latlng = latlngFromMercator(polygon[0]);
      latlngs.push(new GLatLng(latlng[0], latlng[1]));
      return new GPolygon(latlngs);
    }


})();
